#ifndef PINQTASK_H
#define PINQTASK_H

#include <e32base.h>
#include <ES_SOCK.h>
#include <IN_SOCK.h>

#define PINQTASKVER 1
#define PINQTASKPREFVER 2
#define PINQDEFPKTSIZE 64
#define PINQDEFPKTCOUNT 4
#define PINQDEFDELAY    1
#define PINQDEFTIMEOUT  2
#define PINQDEFDNSTIMEOUT  30

class RWriteStream;
class RReadStream;
class CPinQTask : public CActive
	{
public:
	enum TState
		{EStopped,ELookingUp,EOpenning,ESending,ESent,EReceiving,EReceived,EDelay};
	enum TErrorCode
		{ENoError,ETimeout,ESeq,ESystemError};
	class TPacket
		{
public:
		TPacket* iNext;
		CPinQTask* iTask;
		TUint iTime;//msecs
		TUint iSeq;
		TUint iReceSeq;
		TErrorCode iError;
		};
	class MObserver
		{
public:
		/*
		 virtual void Started()=0;
		 virtual void Finished()=0;
		 virtual void Cancelled()=0;
		 virtual void Sent()=0;
		 */
		virtual void
				TaskStateChangedL(const CPinQTask& aTask, TState aNewState)=0;
		//virtual void TaskErrorL(const CPinQTask& aTask);
		//virtual void PacketReceivedL(const CPinQTask::TPacket& aPacket)=0;
		//virtual void PacketSentL(const CPinQTask::TPacket& aPacket)=0;
		//virtual void TaskErrorL(CPinQTask& aTask)=0;
		};

	class CPref : public CBase
		{
public:
		CPref();
		~CPref();

		inline TInt Category() const
			{
			return iCategory;
			}
		inline TUint Delay() const
			{
			return iDelay;
			}
		inline TUint DnsTimeout() const
			{
			return iDnsTimeout;
			}
		inline TUint Timeout() const
			{
			return iTimeout;
			}
		inline TUint PktSize() const
			{
			return iPktSize;
			}
		inline TUint PktCount() const
			{
			return iPktCount;
			}
		inline TBool Endless() const
			{
			return iEndless;
			}
		inline TBool Loop() const
			{
			return iLoop;
			}
		inline const TDesC& Name() const
			{
			return iName ? *iName : KNullDesC();
			}
		inline const TDesC& Note() const
			{
			return iNote ? *iNote : KNullDesC();
			}

		inline void SetCategory(TInt aCategory)
			{
			iCategory = aCategory;
			}
		inline void SetDelay(TInt aDelay)
			{
			iDelay=aDelay;
			}
		inline void SetTimeout(TInt aTimeout)
			{
			iTimeout=aTimeout;
			}
		inline void SetDnsTimeout(TInt aDnsTimeout)
			{
			iDnsTimeout=aDnsTimeout;
			}
		inline void SetPktSize(TInt aPktSize)
			{
			iPktSize = aPktSize;
			}
		inline void SetPktCount(TInt aPktCount)
			{
			iPktCount = aPktCount;
			}
		inline void SetEndless(TBool aEndless)
			{
			iEndless = aEndless;
			}
		inline void SetLoop(TBool aLoop)
			{
			iLoop = aLoop;
			}
		void SetNameL(const TDesC& aName);
		void SetNoteL(const TDesC& aText);

		void ExternalizeL(RWriteStream& aStream) const;
		void InternalizeL(RReadStream& aStream);
		void Reset();
private:
		TInt iCategory;
		TUint iPktSize;
		TUint iPktCount;
		TUint iDelay;
		TUint iTimeout;
		TUint iDnsTimeout;
		TInt8 iEndless;
		TInt8 iLoop;
		HBufC* iName;
		HBufC* iNote;
		};
	class CTimeout : public CActive
		{
public:
		CTimeout(CPinQTask& aTask);
		~CTimeout();
		void ConstructL();
		void Start();
private:
		//Active Object framework
		virtual void RunL();
		virtual void DoCancel();
		virtual TInt RunError(TInt aError);
private:
		RTimer iTimer;
		CPinQTask& iTask;
		};
public:
	static CPinQTask* NewL();
	static CPinQTask* NewLC();
	static CPinQTask* NewL(const CPref& aPref);
	static CPinQTask* NewLC(const CPref& aPref);
	~CPinQTask();

	inline TUid Uid() const
		{
		return iUid;
		}
	inline TState State() const
		{
		return iState;
		}
	inline TErrorCode Error() const
		{
		return iError;
		}
	inline TInt SysError() const
		{
		return iErrorCode;
		}
	inline TInt PacketsCount() const
		{
		return iCount;
		}
	inline TInt FirstSeq() const
		{
		return iCount==0 ? 0 : iSeq-(iCount-1);
		}
	inline TInt LastSeq() const
		{
		return iSeq;
		}
	inline TPacket* LastPacket() const
		{
		return iLast;
		}
	inline TPacket* PreviousPacket() const
		{
		return iPrevious;
		}
	inline TPacket* FirstPacket() const
		{
		return iFirst;
		}
	inline const TInt DnsTime() const
		{
		return iDnsTime;
		}
	inline CPref& Pref()
		{
		return iPref;
		}
	inline const CPref& Pref() const
		{
		return iPref;
		}
	inline void SetUid(TUid aUid)
		{
		iUid=aUid;
		}
	//Serialization
	void ExternalizeL(RWriteStream& aStream) const;
	void InternalizeL(RReadStream& aStream);
	//API
	//	void	SetState(TState aState,MObserver& aObserver); //Issue request
	void StartL(MObserver& aObserver);
	void AbortL();
	inline const TDesC& StateName() const
		{
		return CPinQTask::StateName(iState);
		}
	static const TDesC& StateName(CPinQTask::TState aState);
	//Active Object framework
	virtual void RunL();
	virtual void DoCancel();
	virtual TInt RunError(TInt aError);

private:
	CPinQTask();
	void ConstructL();
	void ConstructL(const CPref& pref);
	void ResetInternal();
	void SetStateL(TState aState);

	void CPinQTask::DeletePackets();
	CPinQTask::TPacket* CPinQTask::AddPacket(TUint aSeq, TUint aTime);

	void OnAlarmL();

	void OpenL();
	void OpenL(TUint32 aAddr);
	void SendToL();
	void RecvFromL();
	void OnSentL();
	void OnRecvdL();
	void NextPingL();

private:
	CPref iPref;
	TUid iUid;
	TState iState;
	MObserver* iObserver;
	TPacket* iFirst;
	TPacket* iLast;
	TPacket* iPrevious;
	TUint iCount;//zero-based lenght of list

	RSocketServ iSocketServ;
	RSocket iSocket;

	CTimeout iTimeout;
	RTimer iTimer;

	RHostResolver iResolver;
	TNameEntry iNameEntry;
	TNameRecord iNameRecord;
	TInetAddr iAddress;
	TUint16 iSeq;// 1-based number of last packet
	HBufC8 *iSendBuf;
	HBufC8 *iReceBuf;
	TPtr8 iReceBufPtr;
	TTime iSentTime;
	//TBool iErrorState; //indicates error state
	TErrorCode iError; //my own error codes
	TInt iErrorCode; //underlaying error code
	TInt iDnsTime;//Tenth of sec
	};
// vim: ts=2:sw=2
#endif
